// Copyright 2024 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package modelmigration

import (
	"testing"

	"github.com/juju/description/v10"
	"github.com/juju/tc"
	"go.uber.org/mock/gomock"

	"github.com/juju/juju/core/blockdevice"
	coreerrors "github.com/juju/juju/core/errors"
	"github.com/juju/juju/core/machine"
)

type exportSuite struct {
	coordinator *MockCoordinator
	service     *MockExportService
}

func TestExportSuite(t *testing.T) {
	tc.Run(t, &exportSuite{})
}

func (s *exportSuite) setupMocks(c *tc.C) *gomock.Controller {
	ctrl := gomock.NewController(c)

	s.coordinator = NewMockCoordinator(ctrl)
	s.service = NewMockExportService(ctrl)

	return ctrl
}

func (s *exportSuite) newExportOperation() *exportOperation {
	return &exportOperation{
		service: s.service,
	}
}

func (s *exportSuite) TestExport(c *tc.C) {
	defer s.setupMocks(c).Finish()

	dst := description.NewModel(description.ModelArgs{})
	dst.AddMachine(description.MachineArgs{
		Id: "666",
	})
	m := dst.Machines()
	c.Assert(m, tc.HasLen, 1)
	c.Assert(m[0].BlockDevices(), tc.HasLen, 0)

	blockDevices := map[machine.Name][]blockdevice.BlockDevice{
		"666": {{
			DeviceName:      "foo",
			DeviceLinks:     []string{"a-link"},
			FilesystemLabel: "label",
			FilesystemUUID:  "device-uuid",
			HardwareId:      "hardware-id",
			WWN:             "wwn",
			BusAddress:      "bus-address",
			SerialId:        "serial-id",
			SizeMiB:         100,
			FilesystemType:  "ext4",
			InUse:           true,
			MountPoint:      "/path/to/here",
		}},
	}
	s.service.EXPECT().GetBlockDevicesForAllMachines(
		gomock.Any()).Return(blockDevices, nil)

	op := s.newExportOperation()
	err := op.Execute(c.Context(), dst)
	c.Assert(err, tc.ErrorIsNil)

	m = dst.Machines()
	c.Assert(m, tc.HasLen, 1)
	c.Assert(m[0].BlockDevices(), tc.HasLen, 1)
	bd := m[0].BlockDevices()[0]
	c.Check(bd.Name(), tc.Equals, "foo")
	c.Check(bd.Links(), tc.DeepEquals, []string{"a-link"})
	c.Check(bd.Label(), tc.Equals, "label")
	c.Check(bd.UUID(), tc.Equals, "device-uuid")
	c.Check(bd.HardwareID(), tc.Equals, "hardware-id")
	c.Check(bd.WWN(), tc.Equals, "wwn")
	c.Check(bd.BusAddress(), tc.Equals, "bus-address")
	c.Check(bd.SerialID(), tc.Equals, "serial-id")
	c.Check(bd.Size(), tc.Equals, uint64(100))
	c.Check(bd.FilesystemType(), tc.Equals, "ext4")
	c.Check(bd.InUse(), tc.IsTrue)
	c.Check(bd.MountPoint(), tc.Equals, "/path/to/here")
}

func (s *exportSuite) TestExportMachineNotFound(c *tc.C) {
	defer s.setupMocks(c).Finish()

	dst := description.NewModel(description.ModelArgs{})

	blockDevices := map[machine.Name][]blockdevice.BlockDevice{
		"666": {{DeviceName: "foo"}},
	}
	s.service.EXPECT().GetBlockDevicesForAllMachines(gomock.Any()).
		Return(blockDevices, nil)

	op := s.newExportOperation()
	err := op.Execute(c.Context(), dst)
	c.Assert(err, tc.ErrorIs, coreerrors.NotFound)
}
